package service

import (
	"encoding/json"
	"fmt"
	ClickHouse "gin/database"
	"gin/model"
	"gin/types"
	"gorm.io/gorm"
	"reflect"
	"strconv"
	"strings"
)

type Entity struct {
}

func (e *Entity) GetEntityRelationInfo(entityIds []int64, relationType string, tenantId int64, page []int, initialEpisodeCode string, showingsNumber string) (res []types.GetEntityRelationInfoRes, err error) {
	var EntityProjectData model.Entity // 获取实体项目数据
	var project model.Project          // 获取项目信息
	var sourceProjectEntityIds []int64 // 获取甲方项目实体ID

	//1.获取实体对应的项目ID和自身的Code码
	ClickHouse.DB.Model(&model.Entity{}).
		Where("id in ?", entityIds).
		Select("project_id,code,module_id,initial_episode_code,showings_number").
		Take(&EntityProjectData)
	//2.获取项目信息
	projectErr := ClickHouse.DB.Model(&model.Project{}).Where("id = ?", EntityProjectData.ProjectId).First(&project).Error
	if projectErr != nil {
		return
	}
	projectId := project.Id
	//3.如果是外包项目就拿着甲方项目ID和乙方实体Code找到甲方项目里的关卡ID
	if project.Type == "outsource" {
		modelModule := model.Module{}
		entityProjectDataModule, errData := modelModule.GetById(uint64(EntityProjectData.ModuleId))
		if errData != nil {
			return
		}

		var entityProjectDataWhere string
		if entityProjectDataModule.Code == "shot" || entityProjectDataModule.Code == "storyboard" {
			entityProjectDataWhere = fmt.Sprintf("project_id = %d and initial_episode_code = '%s' and showings_number ='%s' and code = '%s' and module_id = %d", project.BelongProjectId, EntityProjectData.InitialEpisodeCode, EntityProjectData.ShowingsNumber, EntityProjectData.Code, EntityProjectData.ModuleId)
		} else {
			entityProjectDataWhere = fmt.Sprintf("project_id = %d and code = %s and module_id = %d", project.BelongProjectId, EntityProjectData.Code, EntityProjectData.ModuleId)
		}

		EntityError := ClickHouse.DB.Model(&model.Entity{}).
			Where(entityProjectDataWhere).
			Pluck("id", &sourceProjectEntityIds).
			Error
		if EntityError != nil {
			return
		}
		entityIds = sourceProjectEntityIds
		projectId = uint64(project.BelongProjectId)
	}

	switch relationType {
	case "by_level_to_asset":
		var shotAsset []string
		dbs := ClickHouse.DB.Where("project_id = ?", projectId)

		if len(initialEpisodeCode) > 0 {
			dbs = dbs.Where("initial_episode_code = ?", initialEpisodeCode)
		}

		if len(showingsNumber) > 0 {
			dbs = dbs.Where("showings_number = ?", showingsNumber)
		}

		//4.通过关卡找出镜头
		var entityIdStr []string
		for _, entityId := range entityIds {
			entityIdStr = append(entityIdStr, fmt.Sprintf("'%d'", entityId))
		}

		dbs = dbs.Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'shot_level')),[%s])", strings.Join(entityIdStr, ",")))

		moduleModel := model.Module{}
		shotModule, errs := moduleModel.GetByCode("shot")
		if errs != nil {
			err = errs
			return
		}

		err = ClickHouse.DB.Model(&model.Entity{}).
			Where(dbs).
			Where("module_id =?", shotModule.Id).
			Pluck("ifNull(simpleJSONExtractString(json, 'shot_asset'),'') as shot_asset", &shotAsset).Error

		shotAssetString := strings.Split(strings.Join(shotAsset, ","), ",")
		//去重
		shotAssetStringMap := make(map[string]string)
		var shotAssetStringArray []int64
		for _, assetString := range shotAssetString {
			_, ok := shotAssetStringMap[assetString]
			if !ok && assetString != "null" && assetString != "" {
				shotAssetStringMap[assetString] = assetString
				shotAssetStringArray = append(shotAssetStringArray, IntVal(assetString))
			}
		}

		if len(shotAssetStringArray) == 0 {
			return
		}

		ClickHouse.DB.Model(&model.Entity{}).
			Where("id in ?", shotAssetStringArray).
			Where("simpleJSONExtractInt(json, 'asset_status') != ?", 3).
			Where("JSONLength(JSONExtractString(json, 'asset_deprecate_data')) = ?", 0).
			Offset((page[0] - 1) * page[1]).
			Limit(page[1]).
			Select("id,name,code,initial_episode_code,showings_number,simpleJSONExtractString(entity.json, 'asset_grade') as grade,simpleJSONExtractString(entity.json, 'asset_category') as category").
			Find(&res)
	case "by_asset_to_level":
		dbs := ClickHouse.DB

		moduleModel := model.Module{}
		var entityIdStr []string
		for _, entityId := range entityIds {
			entityIdStr = append(entityIdStr, fmt.Sprintf("'%d'", entityId))
		}

		dbs = dbs.Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'level_asset')),[%s])", strings.Join(entityIdStr, ",")))

		levelModule, errs := moduleModel.GetByCode("level")
		if errs != nil {
			err = errs
			return
		}
		if len(initialEpisodeCode) > 0 {
			dbs = dbs.Where("initial_episode_code = ?", initialEpisodeCode)
		}
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("module_id = ? and project_id = ?", levelModule.Id, projectId).
			Where(dbs).
			Where("simpleJSONExtractInt(json, 'level_status') != ? and JSONLength(JSONExtractString(json, 'level_deprecate_data')) = ?", 3, 0).
			Select("id,name,code,initial_episode_code,showings_number,entity_id").
			Offset((page[0] - 1) * page[1]).
			Limit(page[1]).
			Find(&res).Error

	case "by_level_to_shot", "by_asset_to_shot":
		dbs := ClickHouse.DB

		moduleModel := model.Module{}
		module, errs := moduleModel.GetById(uint64(EntityProjectData.ModuleId))
		if errs != nil {
			err = errs
			return
		}

		var entityIdStr []string
		for _, entityId := range entityIds {
			entityIdStr = append(entityIdStr, fmt.Sprintf("'%d'", entityId))
		}

		dbs = dbs.Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'shot_%s')),[%s])", module.Code, strings.Join(entityIdStr, ",")))

		shotModule, errss := moduleModel.GetByCode("shot")
		if errss != nil {
			err = errss
			return
		}
		if len(initialEpisodeCode) > 0 {
			dbs = dbs.Where("initial_episode_code = ?", initialEpisodeCode)
		}
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("module_id = ? and project_id = ?", shotModule.Id, projectId).
			Where(dbs).
			Where("simpleJSONExtractInt(json, 'shot_status') != ?", 3).
			Where("JSONLength(JSONExtractString(json, 'shot_deprecate_data')) = ?", 0).
			Select("id,name,code,initial_episode_code,showings_number,entity_id").
			Offset((page[0] - 1) * page[1]).
			Limit(page[1]).
			Find(&res).Error

		if err != nil {
			return
		}

		if len(res) == 0 {
			return
		}

		resEntityIds := make([]int64, 0)
		for _, item := range res {
			if item.EntityId != 0 {
				resEntityIds = append(resEntityIds, item.EntityId)
			}
		}

		if len(resEntityIds) == 0 {
			return
		}

		//查找序列
		parentEntity := make([]model.Entity, 0)

		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("id in ?", resEntityIds).
			Select("id,name,code").
			Find(&parentEntity).Error
		if err != nil {
			return
		}

		parentEntityMap := make(map[int64]model.Entity)
		for _, item := range parentEntity {
			parentEntityMap[IntVal(item.Id)] = item
		}

		resValue := make([]types.GetEntityRelationInfoRes, 0)

		for _, item := range res {
			if _, ok := parentEntityMap[item.EntityId]; ok {
				item.ParentName = parentEntityMap[item.EntityId].Name
			}
			resValue = append(resValue, item)
		}

		res = resValue
	case "by_shot_to_asset", "by_shot_to_level":

		var fields string
		var entityWhere string
		var assetFields string
		if relationType == "by_shot_to_asset" {
			fields = "ifNull(simpleJSONExtractString(json, 'shot_asset'),'') as shot_asset"
			entityWhere = "simpleJSONExtractInt(json, 'asset_status') != ? and JSONLength(JSONExtractString(json, 'asset_deprecate_data')) = ?"
			assetFields = "id,name,code,initial_episode_code,showings_number,simpleJSONExtractString(entity.json, 'asset_category') as category,simpleJSONExtractString(entity.json, 'asset_grade') as grade"
		} else {
			fields = "ifNull(simpleJSONExtractString(json, 'shot_level'),'') as shot_level"
			entityWhere = "simpleJSONExtractInt(json, 'level_status') != ? and JSONLength(JSONExtractString(json, 'level_deprecate_data')) = ?"
			assetFields = "id,name,code,initial_episode_code,showings_number"
		}

		var shotAsset []string
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("id in ?", entityIds).
			Select(fields).
			Find(&shotAsset).Error

		shotAssetString := strings.Split(strings.Join(shotAsset, ","), ",")
		//去重
		shotAssetStringMap := make(map[string]string)
		var shotAssetStringArray []int64
		for _, assetString := range shotAssetString {
			_, ok := shotAssetStringMap[assetString]
			if !ok && assetString != "null" && assetString != "" {
				shotAssetStringMap[assetString] = assetString
				shotAssetStringArray = append(shotAssetStringArray, IntVal(assetString))
			}
		}

		if len(shotAssetStringArray) == 0 {
			return
		}

		ClickHouse.DB.Model(&model.Entity{}).
			Where("id in ?", shotAssetStringArray).
			Where(entityWhere, 3, 0).
			Offset((page[0] - 1) * page[1]).
			Limit(page[1]).
			Select(assetFields).
			Find(&res)
	}

	return
}

// GetAssetRelationShotCount 获取资产关联镜头统计
func (e *Entity) GetAssetRelationShotCount(entityId uint64, projectId uint64, page []int) (res []types.GetAssetRelationShotCountRes, err error) {
	entity := model.Entity{}
	res = []types.GetAssetRelationShotCountRes{}
	// 范围暂时只为资产
	ClickHouse.DB.Model(&model.Entity{}).First(&entity, entityId)
	if entity.Id == 0 {
		return
	}

	module := model.Module{}

	entityModule, errs := module.GetById(uint64(entity.ModuleId))

	if errs != nil {
		err = errs
		return
	}

	assetModule := map[string]bool{
		"asset": true,
		"level": true,
	}
	if _, ok := assetModule[entityModule.Code]; !ok {
		return
	}

	err = ClickHouse.DB.Model(&model.Entity{}).
		Where(fmt.Sprintf("has(splitByChar(',',JSONExtractString(json, 'shot_%s')),'%d')", entityModule.Code, entityId)).
		Where("project_id = ?", projectId).
		Offset((page[0] - 1) * page[1]).
		Select("initial_episode_code,project_id,count(id) AS number").
		Group("initial_episode_code,project_id").Find(&res).Error
	return
}

// GetAssetRelationShotIds 获取资产关联镜头id
func (e *Entity) GetAssetRelationShotIds(entityId uint64, initialEpisodeCode []string, projectId uint64) (shotIds []uint64, err error) {
	entity := model.Entity{}
	ClickHouse.DB.Model(&model.Entity{}).First(&entity, entityId)
	module := model.Module{}
	entityModule, errs := module.GetById(uint64(entity.ModuleId))
	if errs != nil {
		err = errs
		return
	}

	err = ClickHouse.DB.Model(&model.Entity{}).
		Where(fmt.Sprintf("has(splitByChar(',',JSONExtractString(json, 'shot_%s')),'%d')", entityModule.Code, entityId)).
		Where("project_id = ? and initial_episode_code in ?", projectId, initialEpisodeCode).
		Pluck("id", &shotIds).Error

	return
}

// InitialEpisodeCodeSql 剧集sql 处理
func InitialEpisodeCodeSql(initialEpisodeCOdeList []types.InitialEpisodeCodeItem, initialEpisodeKey, showingsKey string) (sql string) {

	str := "("
	for _, InitialEpisodeCode := range initialEpisodeCOdeList {
		var showingsSql string
		if len(InitialEpisodeCode.ShowingsNumber) > 0 {

			//都转换为大写
			var ShowingsNumberList []string
			for _, ShowingsNumberItem := range InitialEpisodeCode.ShowingsNumber {
				ShowingsNumberList = append(ShowingsNumberList, strings.ToUpper(ShowingsNumberItem))
			}

			showingsSql = fmt.Sprintf("AND upper(`%s`) IN (%s)", showingsKey, "'"+strings.Join(ShowingsNumberList, "','")+"'")
		}
		str += fmt.Sprintf("(`%s` = '%s' %s) or ", initialEpisodeKey, InitialEpisodeCode.InitialEpisodeCode, showingsSql)
	}
	str = strings.TrimRight(str, " or ")
	str += ")"
	sql = str
	return
}

// InitialEpisodeIdSql 剧集sql 处理
func InitialEpisodeIdSql(initialEpisodeCOdeList []types.InitialEpisodeCodeItem, initialEpisodeKey, showingsKey string) (sql string) {

	str := "("
	for _, InitialEpisodeCode := range initialEpisodeCOdeList {
		var showingsSql string
		if len(InitialEpisodeCode.ShowingsNumber) > 0 {

			//都转换为大写
			var ShowingsNumberList []string
			for _, ShowingsNumberItem := range InitialEpisodeCode.ShowingsNumber {
				ShowingsNumberList = append(ShowingsNumberList, strings.ToUpper(ShowingsNumberItem))
			}

			showingsSql = fmt.Sprintf("AND upper(`%s`) IN (%s)", showingsKey, "'"+strings.Join(ShowingsNumberList, "','")+"'")
		}
		str += fmt.Sprintf("(`%s` = '%d' %s) or ", initialEpisodeKey, InitialEpisodeCode.InitialEpisodeId, showingsSql)
	}
	str = strings.TrimRight(str, " or ")
	str += ")"
	sql = str
	return
}

// GetAssetRelationShotList 获取资产关联的镜头列表
func (e *Entity) GetAssetRelationShotList(entityId uint64, initialEpisodeCode []string) (res []types.GetAssetRelationShotListRes, err error) {
	entity := model.Entity{}
	ClickHouse.DB.Model(&model.Entity{}).Where("id=?", entityId).Take(&entity)
	module := model.Module{}
	entityModule, err := module.GetById(uint64(entity.ModuleId))
	if err != nil {
		return
	}

	shotModule, err := module.GetByCode("shot")
	if err != nil {
		return
	}

	var shotList []model.Shot

	db := ClickHouse.DB.Model(&model.Entity{}).
		Where(fmt.Sprintf("has(splitByChar(',',JSONExtractString(json, 'shot_%s')),'%d')", entityModule.Code, entityId)).
		Where("project_id = ?  and module_id = ?", entity.ProjectId, shotModule.Id)

	if len(initialEpisodeCode) > 0 {
		db = db.Where("initial_episode_code in ?", initialEpisodeCode)
	}

	err = db.
		Select("id,name,code,initial_episode_code,showings_number,remark,json").
		Order("initial_episode_code asc,showings_number asc").
		Find(&shotList).Error

	//筛选出未封板的剧集
	var episodeList []string
	episodeListMap := map[string]string{}
	for _, shotItem := range shotList {
		if _, ok := episodeListMap[shotItem.InitialEpisodeCode]; !ok {
			episodeList = append(episodeList, shotItem.InitialEpisodeCode)
			episodeListMap[shotItem.InitialEpisodeCode] = shotItem.InitialEpisodeCode
		}

	}

	var episodeCodeList []string

	episodeCodeListMap := map[string]string{}
	if len(episodeList) > 0 {
		moduleModel := model.Module{}
		episodeModel, errors := moduleModel.GetByCode("episode")
		if errors != nil {
			return
		}

		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("project_id=? and module_id=? and code in ? and JSONExtractString(json, 'episode_is_seal') != 'yes'", entity.ProjectId, episodeModel.Id, episodeList).
			Pluck("code", &episodeCodeList).
			Error

		for _, episodeCodeListItem := range episodeCodeList {
			episodeCodeListMap[episodeCodeListItem] = episodeCodeListItem
		}
	}

	epMap := map[string]int{}

	res = make([]types.GetAssetRelationShotListRes, 0)
	statusService := Status{}
	statusMapById, err := statusService.getStatusById()
	if err != nil {
		return
	}
	for _, shotItem := range shotList {
		if _, ok := episodeCodeListMap[shotItem.InitialEpisodeCode]; !ok {
			continue
		}
		shotEntity := types.EntityWithStatus{Entity: shotItem.Entity}
		_ = json.Unmarshal(shotItem.Json, &shotItem.ShotJson)

		statusId := IntVal(shotItem.ShotStatus)
		if statusId > 0 {
			shotEntity.ShotStatus = *statusMapById[statusId]
		}

		if epMapIndex, ok := epMap[shotItem.InitialEpisodeCode]; !ok {
			res = append(res, types.GetAssetRelationShotListRes{
				InitialEpisodeCodeId: shotItem.InitialEpisodeCode,
				InitialEpisodeCode:   shotItem.InitialEpisodeCode,
				SceneData: []types.GetAssetRelationShotListSceneData{
					{
						ShowingsNumberId: shotItem.ShowingsNumber,
						ShowingsNumber:   shotItem.ShowingsNumber,
						ShotEntity:       []types.EntityWithStatus{shotEntity},
					},
				},
				SceneDataMap: map[string]int{
					shotItem.ShowingsNumber: 0,
				},
			})
			epMap[shotItem.InitialEpisodeCode] = len(res) - 1
		} else {
			if SceneDataMapIndex, exist := res[epMapIndex].SceneDataMap[shotItem.ShowingsNumber]; !exist {
				res[epMapIndex].SceneDataMap[shotItem.ShowingsNumber] = len(res[epMapIndex].SceneData)
				res[epMapIndex].SceneData = append(res[epMapIndex].SceneData, types.GetAssetRelationShotListSceneData{
					ShowingsNumberId: shotItem.ShowingsNumber,
					ShowingsNumber:   shotItem.ShowingsNumber,
					ShotEntity:       []types.EntityWithStatus{shotEntity},
				})
			} else {
				res[epMapIndex].SceneData[SceneDataMapIndex].ShotEntity = append(res[epMapIndex].SceneData[SceneDataMapIndex].ShotEntity, shotEntity)
			}
		}

		res[epMap[shotItem.InitialEpisodeCode]].ShotNumber += 1
		res[epMap[shotItem.InitialEpisodeCode]].SceneData[res[epMap[shotItem.InitialEpisodeCode]].SceneDataMap[shotItem.ShowingsNumber]].ShotNumber += 1
	}

	return
}

// GetAssetRelationShotTaskCardList 获取资产关联的镜头列表
func (e *Entity) GetAssetRelationShotTaskCardList(entityId uint64) (res []types.GetAssetRelationShotTaskCardListRes, err error) {
	var entity model.Entity

	ClickHouse.DB.Model(&model.Entity{}).
		Where("id = ?", entityId).
		Select("id,module_id,code,project_id,json").
		Take(&entity)

	var modules []model.Module
	err = ClickHouse.DB.Model(&model.Module{}).Where("code in ?", []string{"design", "asset", "episode", "level", "storyboard"}).Find(&modules).Error

	if err != nil {
		return
	}

	moduleList := map[string]model.Module{}
	moduleIdMap := map[int64]model.Module{}
	for _, moduleItem := range modules {
		moduleList[moduleItem.Code] = moduleItem
		moduleIdMap[moduleItem.Id] = moduleItem
	}

	designEntityModuleCode := moduleList["design"]
	AssetEntityModuleCode := moduleList["asset"]
	levelEntityModuleCode := moduleList["level"]
	EpisodeEntityModuleCode := moduleList["episode"]
	shotModule := moduleList["storyboard"]

	// 如果是 概念 找到所属的关卡或者资产
	if entity.ModuleId == designEntityModuleCode.Id {
		//判定是资产还是还是关卡
		var designJson model.DesignJson
		_ = json.Unmarshal(entity.Json, &designJson)
		var currentEntityModuleId = AssetEntityModuleCode.Id
		if designJson.DesignCategory == "关卡" {
			currentEntityModuleId = levelEntityModuleCode.Id
		}
		var currentEntity model.Entity
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("code = ? AND project_id = ? AND module_id = ?", entity.Code, entity.ProjectId, currentEntityModuleId).
			Take(&currentEntity).Error

		if err != nil {
			return
		}

		entity = currentEntity
	}

	currentModule, currentModuleOk := moduleIdMap[entity.ModuleId]

	if !currentModuleOk {
		return
	}

	entityWhere := fmt.Sprintf("has(splitByChar(',',JSONExtractString(json, 'storyboard_%s')),'%d')", currentModule.Code, entity.Id)

	type newShotStruct struct {
		model.Entity
		EpisodePlanEndTime   string `json:"episode_plan_end_time"`
		EpisodePlanStartTime string `json:"episode_plan_start_time"`
		EpisodeStatus        int64  `json:"episode_status"`
	}
	var shotList []newShotStruct // 查询当前实体 [entityId],被关联的集
	err = ClickHouse.DB.Model(&model.Entity{}).
		Where("project_id = ? and module_id = ?", entity.ProjectId, shotModule.Id).
		Where(entityWhere).
		Select("entity.id as id,name,entity.code as code,entity.initial_episode_code as initial_episode_code,entity.showings_number as showings_number,entity.remark as remark,entity.plan_start_time as plan_start_time,"+
			"simpleJSONExtractUInt(episode.json, 'episode_status') as episode_status,episode.plan_start_time as episode_plan_start_time,episode.plan_end_time as episode_plan_end_time").
		Joins("inner join entity as episode on episode.project_id = entity.project_id and episode.code = entity.initial_episode_code and episode.module_id = ?", EpisodeEntityModuleCode.Id).
		Order("entity.initial_episode_code asc,entity.showings_number asc").
		Find(&shotList).Error

	if err != nil {
		return
	}

	epMap := map[string]int{}

	res = make([]types.GetAssetRelationShotTaskCardListRes, 0)
	statusService := Status{}
	statusMapById, err := statusService.getStatusById()
	if err != nil {
		return
	}

	status, err := statusService.GetStatusCodeMap(map[string]string{
		"filter": fmt.Sprintf("code in (%s)", strings.Join([]string{"'not_started'"}, ",")),
		"field":  "id,name,code,color,icon,correspond",
	})

	for _, shotItem := range shotList {

		shotEntity := types.EntityTaskCardWithStatus{Entity: shotItem.Entity}
		EpisodeStatusId := IntVal(shotItem.EpisodeStatus)
		shotEntity.EpisodeStatus = status["not_started"]
		if EpisodeStatusId > 0 {
			shotEntity.EpisodeStatus = *statusMapById[EpisodeStatusId]
		}

		if epMapIndex, ok := epMap[shotItem.InitialEpisodeCode]; !ok {
			res = append(res, types.GetAssetRelationShotTaskCardListRes{
				InitialEpisodeCodeId: shotItem.Id,
				InitialEpisodeCode:   shotItem.InitialEpisodeCode,
				SceneData: []types.GetAssetRelationShotTaskCardListSceneData{
					{
						ShowingsNumberId: shotItem.ShowingsNumber,
						ShowingsNumber:   shotItem.ShowingsNumber,
						ShotEntity:       []types.EntityTaskCardWithStatus{shotEntity},
					},
				},
				SceneDataMap: map[string]int{
					shotItem.ShowingsNumber: 0,
				},
				EpisodeIsSeal:        shotItem.EpisodeIsSeal,
				EpisodeIsShow:        shotItem.EpisodeIsShow,
				PlanStartTime:        shotItem.PlanStartTime,
				EpisodePlanStartTime: shotItem.EpisodePlanStartTime,
				EpisodePlanEndTime:   shotItem.EpisodePlanEndTime,
				EpisodeStatus:        shotEntity.EpisodeStatus,
			})
			epMap[shotItem.InitialEpisodeCode] = len(res) - 1
		} else {
			if SceneDataMapIndex, exist := res[epMapIndex].SceneDataMap[shotItem.ShowingsNumber]; !exist {
				res[epMapIndex].SceneDataMap[shotItem.ShowingsNumber] = len(res[epMapIndex].SceneData)
				res[epMapIndex].SceneData = append(res[epMapIndex].SceneData, types.GetAssetRelationShotTaskCardListSceneData{
					ShowingsNumberId: shotItem.ShowingsNumber,
					ShowingsNumber:   shotItem.ShowingsNumber,
					ShotEntity:       []types.EntityTaskCardWithStatus{shotEntity},
				})
			} else {
				res[epMapIndex].SceneData[SceneDataMapIndex].ShotEntity = append(res[epMapIndex].SceneData[SceneDataMapIndex].ShotEntity, shotEntity)
			}
		}

		res[epMap[shotItem.InitialEpisodeCode]].ShotNumber += 1
		res[epMap[shotItem.InitialEpisodeCode]].SceneData[res[epMap[shotItem.InitialEpisodeCode]].SceneDataMap[shotItem.ShowingsNumber]].ShotNumber += 1
	}
	return
}

// GetMultipleEntityRelationIds 获取多个实体的关联ids
func (e *Entity) GetMultipleEntityRelationIds(entityIds []int64) (res map[int64]types.GetMultipleEntityRelationIdsRes, err error) {
	var EntityProjectData []model.Entity // 获取实体项目数据
	var project model.Project            // 获取项目信息
	var sourceProjectEntityIds []int64   // 获取甲方项目实体ID
	res = map[int64]types.GetMultipleEntityRelationIdsRes{}
	moduleModel := model.Module{}

	//1.获取实体对应的项目ID和自身的Code码
	err = ClickHouse.DB.Model(&model.Entity{}).
		Where("id in ?", entityIds).
		Select("id,project_id,code,module_id,initial_episode_code,showings_number").
		Find(&EntityProjectData).Error

	if len(EntityProjectData) == 0 {
		return
	}

	//2.获取项目信息
	projectErr := ClickHouse.DB.Model(&model.Project{}).Where("id = ?", EntityProjectData[0].ProjectId).First(&project).Error
	if projectErr != nil {
		return
	}
	projectId := project.Id
	entityProjectDataModule, errData := moduleModel.GetById(uint64(EntityProjectData[0].ModuleId))
	if errData != nil {
		return
	}
	//3.如果是外包项目就拿着甲方项目ID和乙方实体Code找到甲方项目里的关卡ID
	outsideEntityMap := map[int64]int64{}
	if project.Type == "outsource" {
		projectId = uint64(project.BelongProjectId)
		partyADB := ClickHouse.DB

		insideMap := map[string]int64{}
		if entityProjectDataModule.Code == "shot" {
			for _, EntityProjectDataItem := range EntityProjectData {
				partyADB = partyADB.Or("initial_episode_code = ? and showings_number =? and code = ?", EntityProjectDataItem.InitialEpisodeCode, EntityProjectDataItem.ShowingsNumber, EntityProjectDataItem.Code)

				insideMap[strings.Join([]string{EntityProjectDataItem.InitialEpisodeCode, EntityProjectDataItem.ShowingsNumber, EntityProjectDataItem.Code}, "_")] =
					int64(EntityProjectDataItem.Id)
			}
		} else {
			var EntityProjectDataCodes []string
			for _, EntityProjectDataItem := range EntityProjectData {
				EntityProjectDataCodes = append(EntityProjectDataCodes, EntityProjectDataItem.Code)
				insideMap[EntityProjectDataItem.Code] = int64(EntityProjectDataItem.Id)
			}
			partyADB = partyADB.Or("code in ?", EntityProjectDataCodes)
		}

		var entityDataList []model.Entity
		EntityError := ClickHouse.DB.Model(&model.Entity{}).
			Where("project_id = ? and module_id = ?", projectId, entityProjectDataModule.Id).
			Where(partyADB).
			Select("id,project_id,code,module_id,initial_episode_code,showings_number").
			Find(&entityDataList).
			Error

		for _, entityDataListItem := range entityDataList {
			sourceProjectEntityIds = append(sourceProjectEntityIds, int64(entityDataListItem.Id))
			if entityProjectDataModule.Code == "shot" {
				outsideEntityMap[int64(entityDataListItem.Id)] = insideMap[strings.Join([]string{entityDataListItem.InitialEpisodeCode, entityDataListItem.ShowingsNumber, entityDataListItem.Code}, "_")]
			} else {
				outsideEntityMap[int64(entityDataListItem.Id)] = insideMap[entityDataListItem.Code]
			}
		}

		entityIds = sourceProjectEntityIds

		if EntityError != nil {
			return
		}
	}

	switch entityProjectDataModule.Code {
	case "level":
		var shotList []struct {
			Id        int64  `json:"id" gorm:"column:id"`
			ShotLevel string `json:"shot_level" gorm:"column:shot_level"`
			ShotAsset string `json:"shot_asset" gorm:"column:shot_asset"`
		}

		//4.通过关卡找出镜头
		var entityIdStr []string
		for _, entityId := range entityIds {
			entityIdStr = append(entityIdStr, fmt.Sprintf("'%d'", entityId))
		}

		shotModule, errs := moduleModel.GetByCode("shot")
		if errs != nil {
			err = errs
			return
		}

		//通过镜头查资产
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("project_id = ? and module_id =?", projectId, shotModule.Id).
			Where("simpleJSONExtractInt(json, 'shot_status') != ?", 3).
			Where("JSONLength(JSONExtractString(json, 'shot_deprecate_data')) = ?", 0).
			Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'shot_level')),[%s])", strings.Join(entityIdStr, ","))).
			Select("id,simpleJSONExtractString(json, 'shot_level') as shot_level,ifNull(simpleJSONExtractString(json, 'shot_asset'),'') as shot_asset").
			Find(&shotList).Error

		levelShotMap := map[int64][]int64{}

		shotAssetMap := map[int64][]int64{}

		for _, shotItem := range shotList {

			if shotItem.ShotAsset != "" {
				for _, ShotAssetItem := range strings.Split(shotItem.ShotAsset, ",") {
					currentShotAsset, _ := strconv.ParseInt(ShotAssetItem, 10, 64)
					shotAssetMap[shotItem.Id] = append(shotAssetMap[shotItem.Id], currentShotAsset)
				}
			}

			currentShotLevel := strings.Split(shotItem.ShotLevel, ",")

			for _, currentShotLevelItem := range currentShotLevel {
				for _, entityId := range entityIds {
					if currentShotLevelItem == strconv.FormatInt(entityId, 10) {

						//如果存在则不添加
						var isExist = true
						for _, levelShotMapItem := range levelShotMap[entityId] {
							if isExist && levelShotMapItem == shotItem.Id {
								isExist = false
								continue
							}
						}

						if isExist {
							levelShotMap[entityId] = append(levelShotMap[entityId], shotItem.Id)
						}

						continue
					}
				}
			}
		}

		levelAssetMap := map[int64][]int64{}
		for levelShotMapIndex, levelShotMapItem := range levelShotMap {
			var currentShotAssetArray [][]int64
			for _, levelShotMapValue := range levelShotMapItem {
				currentShotAssetArray = append(currentShotAssetArray, shotAssetMap[levelShotMapValue])
			}
			levelAssetMap[levelShotMapIndex] = ArrayCombine(currentShotAssetArray)
		}

		for _, entityId := range entityIds {
			if outsideEntityValue, ok := outsideEntityMap[entityId]; ok {
				res[outsideEntityValue] = types.GetMultipleEntityRelationIdsRes{
					AssetIds: levelAssetMap[entityId],
					ShotIds:  levelShotMap[entityId],
				}
			} else {
				res[entityId] = types.GetMultipleEntityRelationIdsRes{
					AssetIds: levelAssetMap[entityId],
					ShotIds:  levelShotMap[entityId],
				}
			}

		}

	case "asset":
		var entityIdStr []string
		for _, entityId := range entityIds {
			entityIdStr = append(entityIdStr, fmt.Sprintf("'%d'", entityId))
		}

		codesModuleMap, errs := moduleModel.GetByCodesMap([]string{"level", "shot"})
		if errs != nil {
			err = errs
			return
		}

		// asset to level
		var levelList []struct {
			Id         int64  `json:"id" gorm:"column:id"`
			LevelAsset string `json:"level_asset" gorm:"column:level_asset"`
		}

		var shotList []struct {
			Id        int64  `json:"id" gorm:"column:id"`
			ShotAsset string `json:"shot_asset" gorm:"column:shot_asset"`
		}

		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("project_id = ? and module_id = ?", projectId, codesModuleMap["level"].Id).
			Where("simpleJSONExtractInt(json, 'level_status') != ? and JSONLength(JSONExtractString(json, 'level_deprecate_data')) = ?", 3, 0).
			Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'level_asset')),[%s])", strings.Join(entityIdStr, ","))).
			Select("id,simpleJSONExtractString(json, 'level_asset') as level_asset").
			Find(&levelList).Error

		// asset to shot
		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("project_id = ? and module_id = ?", projectId, codesModuleMap["shot"].Id).
			Where("simpleJSONExtractInt(json, 'shot_status') != ? and JSONLength(JSONExtractString(json, 'shot_deprecate_data')) = ?", 3, 0).
			Where(fmt.Sprintf("hasAny(splitByChar(',',JSONExtractString(json, 'shot_asset')),[%s])", strings.Join(entityIdStr, ","))).
			Select("id,simpleJSONExtractString(json, 'shot_asset') as shot_asset").
			Find(&shotList).Error

		assetLevelMap := map[int64][]int64{}
		for _, levelItem := range levelList {

			currentLevelAsset := strings.Split(levelItem.LevelAsset, ",")

			for _, currentLevelAssetItem := range currentLevelAsset {

				for _, entityId := range entityIds {
					if currentLevelAssetItem == strconv.FormatInt(entityId, 10) {

						//如果存在则不添加
						var isExist = true
						for _, assetLevelMapItem := range assetLevelMap[entityId] {
							if isExist && assetLevelMapItem == levelItem.Id {
								isExist = false
								continue
							}
						}

						if isExist {
							assetLevelMap[entityId] = append(assetLevelMap[entityId], levelItem.Id)
						}

						continue
					}
				}

			}
		}

		assetShotMap := map[int64][]int64{}
		for _, shotItem := range shotList {

			currentShotAsset := strings.Split(shotItem.ShotAsset, ",")

			for _, currentShotAssetItem := range currentShotAsset {

				for _, entityId := range entityIds {
					if currentShotAssetItem == strconv.FormatInt(entityId, 10) {

						//如果存在则不添加
						var isExist = true
						for _, assetShotMapItem := range assetShotMap[entityId] {
							if isExist && assetShotMapItem == shotItem.Id {
								isExist = false
								continue
							}
						}

						if isExist {
							assetShotMap[entityId] = append(assetShotMap[entityId], shotItem.Id)
						}
						continue
					}
				}
			}
		}

		for _, entityId := range entityIds {
			if outsideEntityValue, ok := outsideEntityMap[entityId]; ok {
				res[outsideEntityValue] = types.GetMultipleEntityRelationIdsRes{
					LevelIds: assetLevelMap[entityId],
					ShotIds:  assetShotMap[entityId],
				}
			} else {
				res[entityId] = types.GetMultipleEntityRelationIdsRes{
					LevelIds: assetLevelMap[entityId],
					ShotIds:  assetShotMap[entityId],
				}
			}

		}

	case "shot":
		var shotList []struct {
			Id        int64  `json:"id" gorm:"column:id"`
			ShotAsset string `json:"shot_asset" gorm:"column:shot_asset"`
			ShotLevel string `json:"shot_level" gorm:"column:shot_level"`
		}

		err = ClickHouse.DB.Model(&model.Entity{}).
			Where("id in ?", entityIds).
			Where("simpleJSONExtractInt(json, 'shot_status') != ?", 3).
			Where("JSONLength(JSONExtractString(json, 'shot_deprecate_data')) = ?", 0).
			Select("id,simpleJSONExtractString(json, 'shot_asset') as shot_asset,simpleJSONExtractString(json, 'shot_level') as shot_level").
			Find(&shotList).Error

		for _, shotItem := range shotList {
			var currentShotAsset []int64
			var currentShotLevel []int64
			for _, ShotAssetItem := range strings.Split(shotItem.ShotAsset, ",") {
				ShotAssetItemValue, _ := strconv.ParseInt(ShotAssetItem, 10, 64)
				currentShotAsset = append(currentShotAsset, ShotAssetItemValue)
			}

			for _, ShotLevelItem := range strings.Split(shotItem.ShotLevel, ",") {
				ShotLevelItemValue, _ := strconv.ParseInt(ShotLevelItem, 10, 64)
				currentShotLevel = append(currentShotLevel, ShotLevelItemValue)
			}

			if outsideEntityValue, ok := outsideEntityMap[shotItem.Id]; ok {
				res[outsideEntityValue] = types.GetMultipleEntityRelationIdsRes{
					AssetIds: currentShotAsset,
					LevelIds: currentShotLevel,
				}
			} else {
				res[shotItem.Id] = types.GetMultipleEntityRelationIdsRes{
					AssetIds: currentShotAsset,
					LevelIds: currentShotLevel,
				}
			}

		}

	}

	return
}

// GetMultipleEntityRelationCount 获取关联的统计
func (e *Entity) GetMultipleEntityRelationCount(req types.GetMultipleEntityRelationCountReq) (res types.GetMultipleEntityRelationCountRes, err error) {

	// 本集使用 ,获取使用集的sql
	sql, err := e.dealGetMultipleEntityRelationEpisodeSql(req)
	if err != nil {
		return
	}
	if len(req.ModuleCodeList) <= 0 {
		res, err = e.GetMultipleEntityRelationCountResult(sql, req, req.ModuleCode, req.ModuleCode)
	} else {
		var ModuleCodeMap = make(map[string]bool, 0)
		for _, code := range req.ModuleCodeList {
			ModuleCodeMap[code] = true
		}
		if ModuleCodeMap["asset"] {
			res, err = e.GetMultipleEntityRelationCountResult(sql, req, "design", "asset") // 查概念数量
		}
		if ModuleCodeMap["shot"] {
			res, err = e.GetMultipleEntityRelationCountResult(sql, req, "storyboard", "shot") // 查分镜数量
		}
	}
	return
}

// dealGetMultipleEntityRelationEpisodeSql 处理获取多实体关联中的剧集关系sql
func (e *Entity) dealGetMultipleEntityRelationEpisodeSql(req types.GetMultipleEntityRelationCountReq) (sql string, err error) {
	if len(req.InitialEpisodeCodeList) > 0 || len(req.EpisodeCodes) > 0 {
		if req.EpisodeType == "episode_use" {
			var EpisodeName []string
			EpisodeNameMap := map[string]string{}

			if len(req.EpisodeCodes) > 0 {
				EpisodeName = req.EpisodeCodes
			}

			if len(req.InitialEpisodeCodeList) > 0 {
				for _, v := range req.InitialEpisodeCodeList {
					if _, ok := EpisodeNameMap[v.InitialEpisodeCode]; !ok {
						EpisodeName = append(EpisodeName, v.InitialEpisodeCode)
						EpisodeNameMap[v.InitialEpisodeCode] = v.InitialEpisodeCode
					}
				}
			}

			if len(req.EpisodeCodes) > 0 {
				EpisodeName = req.EpisodeCodes
				var EpisodeIds []string
				err = ClickHouse.DB.Model(&model.Entity{}).Where("project_id = ? and `code` IN (?) and module_id IN (select id from module where code = 'episode')", req.ProjectId, EpisodeName).Pluck("id", &EpisodeIds).Error
				if err != nil {
					return
				}
				sql = fmt.Sprintf("episode_id IN ('%s')", strings.Join(EpisodeIds, "','"))
			}

			if len(req.InitialEpisodeCodeList) > 0 {
				var EpisodeList []struct {
					Id   int64  `json:"id"`
					Code string `json:"code"`
				}

				err = ClickHouse.DB.Model(&model.Entity{}).Where("project_id = ? and `code` IN (?) and module_id IN (select id from module where code = 'episode')", req.ProjectId, EpisodeName).Find(&EpisodeList).Error
				if err != nil {
					return
				}
				var EpisodeMap = make(map[string]int64)
				for _, v := range EpisodeList {
					EpisodeMap[v.Code] = v.Id
				}

				for i, v := range req.InitialEpisodeCodeList {
					req.InitialEpisodeCodeList[i].InitialEpisodeId = EpisodeMap[v.InitialEpisodeCode]
				}
				sql = InitialEpisodeIdSql(req.InitialEpisodeCodeList, "episode_id", "showings_number")
			}
		} else {
			if len(req.EpisodeCodes) > 0 {
				sql = fmt.Sprintf("initial_episode_code IN ('%s')", strings.Join(req.EpisodeCodes, "','"))
			}

			if len(req.InitialEpisodeCodeList) > 0 {
				sql = InitialEpisodeCodeSql(req.InitialEpisodeCodeList, "initial_episode_code", "showings_number")
			}
		}
	}
	return
}

// GetMultipleEntityRelationCountQueryFilter 处理获取多实体关联中的查询条件
func (e *Entity) GetMultipleEntityRelationCountQueryFilter(db *gorm.DB, req types.GetMultipleEntityRelationCountReq, moduleCode string) {
	//实体查询
	if len(req.EntityIds) > 0 {
		db = db.Where("id in ?", req.EntityIds)
	}
	//分类查询
	if len(req.CategoryName) > 0 {
		db = db.Where(fmt.Sprintf("simpleJSONExtractString(entity.json, '%s_category') IN (?)", moduleCode), req.CategoryName)
	}
	if req.EntityName != "" {
		db = db.Where("upper(entity.name)  LIKE ?", fmt.Sprintf("%s%s%s", "%", strings.ToUpper(req.EntityName), "%"))
	}
	//状态查询
	if len(req.Status) > 0 {
		statusService := Status{}
		statusIds, _ := statusService.GetStatusIdsByCode(req.Status)
		db = db.Where(fmt.Sprintf("simpleJSONExtractInt(entity.json, '%s_status') IN (?)", moduleCode), statusIds)
	}
	if req.AssetGrade != "" {
		db = db.Where(fmt.Sprintf("simpleJSONExtractString(entity.json, '%s_grade') = ?", moduleCode), req.AssetGrade)
	}

	if req.ShotProductionMethod != "" {
		db = db.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_production_method') = ?", moduleCode), req.ShotProductionMethod)
	}
	if req.ShotClothSolution != "" {
		db = db.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_cloth_solution') = ?", moduleCode), req.ShotClothSolution)
	}
	if req.ShotFx != "" {
		db = db.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_fx') = ?", moduleCode), req.ShotFx)
	}
	if req.ShotPerformForm != "" {
		db = db.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_perform_form') = ?", moduleCode), req.ShotPerformForm)
	}

	switch req.IsRelate {
	case "yes": //已关联
		db = db.Where("simpleJSONExtractString(entity.json, 'design_relate_level') !=''")
	case "no": // 未关联
		db = db.Where(fmt.Sprintf("((simpleJSONExtractString(`entity`.`json`, '%s_relate_level') is null) or (simpleJSONExtractString(entity.json, '%s_category') = '场景' and simpleJSONExtractString(entity.json, '%s_relate_level') =''))", moduleCode, moduleCode, moduleCode))
	}
	//导演是否收藏
	if req.DirectorStar == "yes" {
		db = db.Where("entity.director_star = 'yes'")
	}
	// 关键镜头
	if req.KeyShot == "yes" {
		db = db.Where("entity.key_shot = 'yes'")
	}
	// 是否新增
	if req.IsAppend == "yes" {
		db = db.Where("entity.is_append = 'yes'")
	}
	if len(req.EntityCreated) >= 2 {
		db = db.Where("entity.created BETWEEN ? and ?", req.EntityCreated[0], req.EntityCreated[1])
	}
}

// GetMultipleEntityRelationAssetCount 获取关联的资产统计
func (e *Entity) GetMultipleEntityRelationAssetCount(db *gorm.DB, req types.GetMultipleEntityRelationCountReq, module model.Module) (res types.GetMultipleEntityRelationCountRes, err error) {
	type listStruct struct {
		Category    string `json:"category"`
		EntityCount int64  `json:"entityCount"`
		SS          int64  `json:"S+"`
		S           int64  `json:"S"`
		A           int64  `json:"A"`
		B           int64  `json:"B"`
		C           int64  `json:"C"`
	}

	var list []listStruct
	moduleCode := module.Code
	err = db.
		Where("project_id = ? and module_id = ?", req.ProjectId, module.Id).
		Select("simpleJSONExtractString(entity.json, '"+moduleCode+"_category') as category,"+
			"count(entity.id) as entity_count,"+
			"count(simpleJSONExtractString(entity.json, '"+moduleCode+"_grade') == 'S+' or null) as `SS`,"+
			"count(simpleJSONExtractString(entity.json, '"+moduleCode+"_grade') == 'S' or null) as `S`,"+
			"count(simpleJSONExtractString(entity.json, '"+moduleCode+"_grade') == 'A' or null) as `A`,"+
			"count(simpleJSONExtractString(entity.json, '"+moduleCode+"_grade') == 'B' or null) as `B`,"+
			"count(simpleJSONExtractString(entity.json, '"+moduleCode+"_grade') == 'C' or null) as `C`").
		Where(fmt.Sprintf("JSONLength(JSONExtractString(entity.json, '%s_deprecate_data')) = ?", moduleCode), 0).
		Group("simpleJSONExtractString(entity.json, '" + moduleCode + "_category')").
		Find(&list).
		Error

	var entityCount int64
	for _, v := range list {
		entityCount += v.EntityCount
		res.CategoryCount = append(res.CategoryCount, types.GetMultipleEntityRelationCountResCategoryCount{
			Category:    v.Category,
			EntityCount: v.EntityCount,
			AssetGradeList: types.AssetGradeStruct{
				SS: v.SS,
				S:  v.S,
				A:  v.A,
				B:  v.B,
				C:  v.C,
			},
		})
	}
	res.EntityCount = entityCount
	return
}

// GetMultipleEntityRelationShotCount 获取关联的镜头统计
func (e *Entity) GetMultipleEntityRelationShotCount(db *gorm.DB, req types.GetMultipleEntityRelationCountReq, module model.Module) (res types.GetMultipleEntityRelationCountRes, err error) {
	moduleCode := module.Code
	type shotStruct struct {
		EntityCount         int64 `json:"entity_count" category:"镜头数量"`          // 镜头数量
		LiteraryDrama       int64 `json:"literary_drama" category:"文戏"`          // 文戏
		MartialArts         int64 `json:"martial_arts" category:"武戏"`            // 武戏
		SolveShots          int64 `json:"solve_shots" category:"解算"`             // 解算
		SpecialEffectsShots int64 `json:"special_effects_shots" category:"特效镜头"` // 特效镜头
	}

	fieldMap := map[string]string{
		"entity_count":          "count(entity.id) as entity_count",
		"martial_arts":          "count((simpleJSONExtractString(entity.json, '" + moduleCode + "_perform_form') = '武戏') or null) as martial_arts",
		"literary_drama":        "count((simpleJSONExtractString(entity.json, '" + moduleCode + "_perform_form') = '文戏') or null) as literary_drama",
		"solve_shots":           "count((simpleJSONExtractString(entity.json, '" + moduleCode + "_cloth_solution') <> '不需要解算') or null) as solve_shots",
		"special_effects_shots": "count((simpleJSONExtractString(entity.json, '" + moduleCode + "_fx') <> '无特效' and simpleJSONExtractString(entity.json, '" + moduleCode + "_fx') != '' ) or null) as special_effects_shots",
	}

	shotFieldMap := map[string]string{}
	var fields []string
	switch req.Type {
	case "":
		shotFieldMap = map[string]string{
			"entity_count":          "镜头总数",
			"martial_arts":          "武戏镜头",
			"solve_shots":           "解算镜头",
			"special_effects_shots": "特效镜头",
		}

		for shotFieldKey, _ := range shotFieldMap {
			fields = append(fields, fieldMap[shotFieldKey])
		}
	case "plan_entity_count":
		shotFieldMap = map[string]string{
			"literary_drama":        "文戏",
			"martial_arts":          "武戏",
			"solve_shots":           "解算",
			"special_effects_shots": "特效",
		}
		for shotFieldKey, _ := range shotFieldMap {
			fields = append(fields, fieldMap[shotFieldKey])
		}
		fields = append(fields, fieldMap["entity_count"])
	}
	//字段
	var shotCountFields = strings.Join(fields, ",")

	//查询sql
	var tmpShotList shotStruct
	err = db.
		Where("project_id = ? and module_id = ?", req.ProjectId, module.Id).
		Where(fmt.Sprintf("JSONLength(JSONExtractString(entity.json, '%s_deprecate_data')) = ?", moduleCode), 0).
		Select(shotCountFields).
		Find(&tmpShotList).
		Error

	//反射
	tmpReflect := reflect.TypeOf(tmpShotList)
	tmpReflectValue := reflect.ValueOf(tmpShotList)
	//通过反射循环获取字段
	for i := 0; i < tmpReflect.NumField(); i++ {
		field := tmpReflect.Field(i)
		//这个拉取到第 i 个字段的值
		count := tmpReflectValue.Field(i).Interface().(int64)
		//field.Tag.Get("json") 获取字段上的标签属性json
		if categoryName, ok := shotFieldMap[field.Tag.Get("json")]; ok {
			res.CategoryCount = append(res.CategoryCount, types.GetMultipleEntityRelationCountResCategoryCount{
				Category:    categoryName,
				EntityCount: count,
			})
		}
	}
	res.EntityCount = tmpShotList.EntityCount
	return
}

// GetMultipleEntityRelationCountResult 获取多实体关联的统计结果
func (e *Entity) GetMultipleEntityRelationCountResult(sql string, req types.GetMultipleEntityRelationCountReq, entityModuleCode string, moduleCodeQuery string) (res types.GetMultipleEntityRelationCountRes, err error) {
	ModuleModule := model.Module{}
	module, _ := ModuleModule.GetByCode(entityModuleCode)

	db := ClickHouse.DB.Model(&model.Entity{})
	//如果sql不为空
	if sql != "" {
		if req.EpisodeType == "episode_use" { // 本集使用
			sql = fmt.Sprintf("select entity_id from entity_episode_relation where project_id = %d and entity_module_id = %d and %s group by entity_id", req.ProjectId, module.Id, sql)
			db = db.Joins(fmt.Sprintf("join (%s) err on err.entity_id = entity.id", sql))
		} else {
			db.Where(sql)
		}
	}
	moduleCode := module.Code
	e.GetMultipleEntityRelationCountQueryFilter(db, req, moduleCode)

	//使用哪个方法
	moduleCode = moduleCodeQuery

	switch {
	case moduleCode == "asset", moduleCode == "level", moduleCode == "design" && req.Type == "plan_entity_count":
		res, err = e.GetMultipleEntityRelationAssetCount(db, req, module)
	case moduleCode == "shot":
		res, err = e.GetMultipleEntityRelationShotCount(db, req, module)
	default: //默认的只查询出总数
		err = db.
			Where("project_id = ? and module_id = ?", req.ProjectId, module.Id).
			Where(fmt.Sprintf("JSONLength(JSONExtractString(entity.json, '%s_deprecate_data')) = ?", module.Code), 0).
			Select("count(entity.id) as entity_count").
			Pluck("entity_count", &res.EntityCount).
			Error
	}
	return
}

// GetEpisodeIdMap 获得剧集id字典
func (e *Entity) GetEpisodeIdMap(where interface{}) (res map[int64]*model.Entity, err error) {
	var episodeList []model.Entity
	err = ClickHouse.DB.
		Model(&model.Entity{}).
		Where(where).
		Where("module_id = (select id from module where code = 'episode' limit 1)").
		Select("id,name,code").Find(&episodeList).Error
	if err != nil {
		return
	}

	res = make(map[int64]*model.Entity)
	for i, entity := range episodeList {
		res[int64(entity.Id)] = &episodeList[i]
	}
	return
}

// GetEpisodeCodeMap 获得剧集code字典
func (e *Entity) GetEpisodeCodeMap(where interface{}) (res map[string]*model.Entity, err error) {
	var episodeList []model.Entity
	err = ClickHouse.DB.
		Model(&model.Entity{}).
		Where(where).
		Where("module_id = (select id from module where code = 'episode' limit 1)").
		Select("id,name,code").Find(&episodeList).Error
	if err != nil {
		return
	}

	res = make(map[string]*model.Entity)
	for i, entity := range episodeList {
		res[entity.Code] = &episodeList[i]
	}
	return
}
